
enum PokerType {
	DIAMOND = 1,  //方块
	CLUB,       //梅花
	HEART,      //红桃
	SPADE,      //黑桃
}

enum PokerLevel {
	LEVEL_3 = 3,
	LEVEL_4,
	LEVEL_5,
	LEVEL_6,
	LEVEL_7,
	LEVEL_8,
	LEVEL_9,
	LEVEL_10,
	LEVEL_J,
	LEVEL_Q,
	LEVEL_K,
	LEVEL_A,
	LEVEL_2,
	LEVEL_SMALL_KING,   //小王
	LEVEL_BIG_KING,     //大王
}

enum SellType {
	ILLEGAL,    //非合法
	SINGLE,     //单个牌
	DOUBLE,     //对子牌
	THREE,      //三张牌
	THREE_ZONES_SINGLE,//三带单
	THREE_ZONES_DOUBLE,//三带对
	FOUR_ZONES_SINGLE,  //四带单
	FOUR_ZONES_DOUBLE,   //四带对
	SINGLE_STRAIGHT,    //单顺子
	DOUBLE_STRAIGHT, //双顺子
	THREE_STRAIGHT,  //三顺子
	FOUR_STRAIGHT,    //四顺子
	THREE_STRAIGHT_WITH_SINGLE, //飞机带单牌
	THREE_STRAIGHT_WITH_DOUBLE,   //飞机带对牌
	FOUR_STRAIGHT_WITH_SINGLE,   //四顺子带单
	FOUR_STRAIGHT_WITH_DOUBLE,   //四顺子带对,
	BOMB,       //炸弹
	KING_BOMB,  //王炸
}

class SellWeight {
	static Single = 1;   //
	static BigSingle = 2;   //2或者大小王
	static Duizi = 3;
	static Three = 4;
	static Shunzi = 5;    //每多一张，权重+1
	static Liandui = 6;    //每多一对，权重+2
	static Fly = 7;       //每对以飞机，在权值基础上+3
	static Bomb = 8;      //
}

class Poker {
	level: number;
	type: number;
	constructor(level: number, type: number) {
		this.level = level;
		this.type = type;
	}
}

export class PokerSell {
	score: number;
	sellType: SellType;
	sellPokers: Array<Poker> = [];
	coreLevel: number;
	/**
	 * 在当前手牌中的索引
	 */
	positions: Array<number> = [];

	/**
	 * 连对是几对，顺子是几顺
	 */
	straightCount: number;

	constructor(sellType: SellType, sellPokers: Array<Poker>, coreLevel: number) {
		this.score = PokerHelper.parseScore(sellType, coreLevel);
		this.sellType = sellType;
		this.sellPokers = sellPokers;
		this.coreLevel = coreLevel;
		this.straightCount = PokerHelper.parseStraightCount(sellPokers, sellType);
	}

	public getCoreLevel() {
		return this.coreLevel;
	}

	public setCoreLevel(coreLevel: number) {
		this.coreLevel = coreLevel;
	}

	public getScore() {
		return this.score;
	}

	public setScore(score: number) {
		this.score = score;
	}

	public getSellType() {
		return this.sellType;
	}

	public setSellType(sellType: SellType) {
		this.sellType = sellType;
	}

	public getSellPokers() {
		return this.sellPokers;
	}

	public setSellPokers(sellPokers: Array<Poker>) {
		this.sellPokers = sellPokers;
	}

	public getStraightCount() {
		return this.straightCount;
	}

	public setStraightCount(straightCount: number) {
		this.straightCount = straightCount;
	}

	public getPositions() {
		return this.positions;
	}

	public setPositions(positions: Array<number>) {
		this.positions = positions;
	}

	public addPositions(positions: Array<number>) {
		if (positions == undefined || positions.length <= 0) {
			return;
		}
		if (this.positions == undefined) {
			this.positions = positions;
		} else {
			positions.forEach((data) => { this.positions.push(data) });
		}
	}
}

class PokerGroup {
	times: number;
	weight: number;

	single: Array<Poker>;           //单张
	singleBig: Array<Poker>;        //单张大牌：2或者大小王
	two: Array<Array<Poker>>;        //对子
	three: Array<Array<Poker>>;      //3张
	shunzi: Array<Array<Poker>>;     //顺子
	liandui: Array<Array<Poker>>;    //连对
	fly: Array<Array<Poker>>;        //飞机
	bombs: Array<Array<Poker>>;      //炸弹

	positions: Array<number>;

	constructor() {
		this.times = 0;
		this.weight = 0;
		this.single = new Array();
		this.singleBig = new Array();
		this.two = new Array();
		this.three = new Array();
		this.shunzi = new Array();
		this.liandui = new Array();
		this.fly = new Array();
		this.bombs = new Array();
		this.positions = new Array();
	}

	public reset() {
		this.times = 0;
		this.weight = 0;
		this.single.length = 0;
		this.singleBig.length = 0;
		this.two.length = 0;
		this.three.length = 0;
		this.shunzi.length = 0;
		this.liandui.length = 0;
		this.fly.length = 0;
		this.bombs.length = 0;
		this.positions.length = 0;
	}

	public printAll() {
		PokerHelper.printPokers("单张：", this.single);

		PokerHelper.printPokers("单张大牌：", this.singleBig);

		for (let pokers of this.two) {
			PokerHelper.printPokers("对子：", pokers);
		}
		for (let pokers of this.three) {
			PokerHelper.printPokers("3张: ", pokers);
		}
		for (let pokers of this.liandui) {
			PokerHelper.printPokers("连对：", pokers);
		}
		for (let pokers of this.shunzi) {
			PokerHelper.printPokers("顺子：", pokers);
		}
		for (let pokers of this.fly) {
			PokerHelper.printPokers("飞机：", pokers);
		}
		for (let pokers of this.bombs) {
			PokerHelper.printPokers("炸弹：", pokers);
		}

		//console.log("sell times: " + this.getTimes() + " weight: " + this.getWeight());
	}

	public addSingle(poker: Poker) {
		this.single.push();
		this.single.push(poker);
	}

	public addSingleBig(poker: Poker) {
		this.singleBig.push(poker);
	}

	public addTwo(pokers: Array<Poker>) {
		this.two.push(pokers);
	}

	public addThree(pokers: Array<Poker>) {
		this.three.push(pokers);
	}

	public addShunzi(pokers: Array<Poker>) {
		this.shunzi.push(pokers);
	}

	public addBomb(pokers: Array<Poker>) {
		this.bombs.push(pokers);
	}

	public sortAll() {
		this.single.sort(function (A, B) {
			return A.level - B.level;
		});
		this.singleBig.sort(function (A, B) {
			return A.level - B.level;
		});
		if (this.two.length > 0) {
			this.two.sort(function (A, B) {
				return A[0].level - B[0].level;
			});
		}
		if (this.three.length > 0) {
			this.three.sort(function (A, B) {
				return A[0].level - B[0].level;
			});
		}
		if (this.shunzi.length > 0) {
			this.shunzi.sort(function (A, B) {
				return A[0].level - B[0].level;
			});
		}
		if (this.liandui.length > 0) {
			this.liandui.sort(function (A, B) {
				return A[0].level - B[0].level;
			});
		}
		if (this.fly.length > 0) {
			this.fly.sort(function (A, B) {
				return A[0].level - B[0].level;
			});
		}
		if (this.bombs.length > 0) {
			this.bombs.sort(function (A, B) {
				return A[0].level - B[0].level;
			});
		}
	}

	public getTimes(): number {
		let count: number = 0;
		let left: number = 0;   //剩余可用于配对的
		count += this.singleBig.length;
		count += this.single.length;
		count += this.two.length;
		left = count;
		if (this.three.length > 0) {
			if (this.three.length > left) {
				count = this.three.length;  //3张可以带对或者单张，手数减1
				left = 0;
			} else {
				left -= this.three.length;
			}
		}

		if (this.fly.length > 0) {
			if (this.fly.length < left) {
				left -= this.fly.length;
			}
		}

		count += this.bombs.length;
		count += this.shunzi.length;
		count += this.liandui.length;

		return count;
	}

	public getWeight(): number {
		let value = this.single.length;
		value += SellWeight.BigSingle * this.singleBig.length;
		value += SellWeight.Duizi * this.two.length;
		value += SellWeight.Three * this.three.length;
		value += SellWeight.Bomb * this.bombs.length;

		if (this.shunzi.length > 0) {
			value += SellWeight.Shunzi;
			if (this.shunzi.length - 5 > 0) {
				value += (this.shunzi.length - 5);
			}
		}
		if (this.fly.length > 0) {
			value += SellWeight.Fly;
			if (this.fly.length - 2 > 0) {
				value += (this.fly.length - 2);
			}
		}
		if (this.liandui.length > 0) {
			value += SellWeight.Liandui;
			if (this.liandui.length - 3 > 0) {
				value += (this.liandui.length - 3);
			}
		}
		return value;
	}

	public getScore() {
		return 0;
	}
}

export class PokerHelper {
	static currentPokerType: number = 0;
	static allBiggerPokerType3P: Array<PokerSell> = null;

	public static clear() {
		PokerHelper.currentPokerType = 0;
		PokerHelper.allBiggerPokerType3P = null;
	}

	public static alisName(poker: Poker): String {
		return poker.level + "@" + poker.type;
	}

	public static printPokers(tag: String, pokers: Array<Poker>) {
		if (null != pokers && pokers.length > 0) {
			let info = (tag == null ? "" : tag);

			for (let poker of pokers) {
				info += poker.level + " ";
			}

			// console.log("=======>", info);
		}
	}

	//检查出牌是否符合
	public static checkSellValid(lastPokerSell: PokerSell, pokers: Array<Poker>) {


		let pokerSell = PokerHelper.checkPokerType(pokers);

		if (pokerSell.getSellType() == SellType.ILLEGAL) {
			return -2;
		}

		if (!lastPokerSell) {
			return 0;
		}
		
		if ((lastPokerSell.getSellType() != pokerSell.getSellType() || lastPokerSell.getSellPokers().length != pokerSell.getSellPokers().length)
			&& pokerSell.getSellType() != SellType.BOMB && pokerSell.getSellType() != SellType.KING_BOMB) {
			//出牌不比配，应该出（lastPokerSell.getSellPokers().length）张牌
			return lastPokerSell.getSellPokers().length;
		}

		if (lastPokerSell.getScore() >= pokerSell.getScore()) {
			//出牌小于上家
			return -1
		}

		//正常
		return 0;
	}

	public static validSells(lastPokerSell: PokerSell, pokers: Array<Poker>): Array<PokerSell> {

		let sells: Array<PokerSell> = PokerHelper.parsePokerSells(pokers);
		if (lastPokerSell == undefined) {
			return sells;
		}

		let validSells: Array<PokerSell> = [];
		for (let sell of sells) {
			if (sell.getSellType() == lastPokerSell.getSellType()) {
				if (sell.getScore() > lastPokerSell.getScore() && sell.getSellPokers().length == lastPokerSell.getSellPokers().length) {
					validSells.push(sell);
				}
			}
			if (sell.getSellType() == SellType.KING_BOMB) {
				validSells.push(sell);
			}
		}
		if (lastPokerSell.getSellType() != SellType.BOMB) {
			for (let sell of sells) {
				if (sell.getSellType() == SellType.BOMB) {
					validSells.push(sell);
				}
			}
		}
		return validSells;
	}

	public static isBomb(sellType: SellType): boolean {
		return (sellType == SellType.BOMB || sellType == SellType.KING_BOMB);
	}

	//出牌提示
	public static hint(pokers: Array<Poker>, shellPokers: Array<Poker>) {
		if (shellPokers == undefined || shellPokers.length <= 0) {
			//如果是空，则是自己牌权, 出最小的单张
			let pokerSell = PokerHelper.findMinPokersGroup(pokers);
			if (pokerSell.getSellType() == SellType.ILLEGAL) {
				pokerSell = PokerHelper.checkPokerType([pokers[pokers.length - 1]]);
				pokerSell.setPositions([pokers.length - 1]);
			}

			return pokerSell;
		}

		let pokerSell = PokerHelper.checkPokerType(shellPokers);

		// console.log("============> hint  pokerSell " + pokerSell.getSellType() + " pokers: " + pokerSell.getSellPokers());
		//如果上家出的牌是炸弹，我们只能用炸弹去打
		if (PokerHelper.allBiggerPokerType3P == null) {
			// PokerHelper.allBiggerPokerType3P = PokerHelper.findAllBiggerPokerType3P(pokers, pokerSell);
			PokerHelper.allBiggerPokerType3P = PokerHelper.findAllBigSellType(pokers, pokerSell);
			if (PokerHelper.allBiggerPokerType3P.length == 0) {
				PokerHelper.allBiggerPokerType3P = PokerHelper.findAllBiggerPokerType3P(pokers, pokerSell);
			}
		}

		// console.log("============> hint  bigger size " + PokerHelper.allBiggerPokerType3P.length + " " + PokerHelper.currentPokerType);
		// console.log("============> hint  bigger poker " + PokerHelper.allBiggerPokerType3P);

		if (PokerHelper.allBiggerPokerType3P.length == 0) {
			return new PokerSell(SellType.ILLEGAL, [], -1);
		} else {
			if (PokerHelper.currentPokerType < PokerHelper.allBiggerPokerType3P.length) {
				let pokerSell3P = PokerHelper.allBiggerPokerType3P[PokerHelper.currentPokerType];
				PokerHelper.currentPokerType++;
				if (PokerHelper.currentPokerType == PokerHelper.allBiggerPokerType3P.length) {
					PokerHelper.currentPokerType = 0;
				}
				return pokerSell3P;
			} else {
				return PokerHelper.allBiggerPokerType3P[PokerHelper.allBiggerPokerType3P.length - 1];
			}
		}
	}

	//获取牌型
	public static checkPokerType(pokers: Array<Poker>): PokerSell {
		if (pokers == undefined || pokers.length <= 0) {
			return new PokerSell(SellType.ILLEGAL, [], -1);
		}

		let levelTable = new Array(20).fill(0);

		pokers.forEach((poker) => {
			levelTable[poker.level]++;
		});

		// console.log("======> checkPokerType pokers:", pokers, levelTable);

		let startIndex = -1;
		let endIndex = -1;
		let count = 0;

		let singleCount = 0;
		let doubleCount = 0;
		let threeCount = 0;
		let threeStartIndex = -1;
		let threeEndIndex = -1;
		let fourCount = 0;
		let fourStartIndex = -1;
		let fourEndIndex = -1;
		for (let index = 0; index < levelTable.length; index++) {
			let value = levelTable[index];
			if (value == 0) {
				continue;
			}
			endIndex = index;
			count++;
			if (startIndex == -1) {
				startIndex = index;
			}
			if (value == 1) {
				singleCount++;
			} else if (value == 2) {
				doubleCount++;
			} else if (value == 3) {
				if (threeStartIndex == -1) {
					threeStartIndex = index;
				}
				threeEndIndex = index;
				threeCount++;
			} else if (value == 4) {
				if (fourStartIndex == -1) {
					fourStartIndex = index;
				}
				fourEndIndex = index;
				fourCount++;
			}
		}

		if (singleCount == doubleCount && singleCount == threeCount && singleCount == 0 && fourCount == 1) {
			return new PokerSell(SellType.BOMB, pokers, startIndex);
		}

		if (singleCount == 2 && startIndex == PokerLevel.LEVEL_SMALL_KING && endIndex == PokerLevel.LEVEL_BIG_KING) {
			return new PokerSell(SellType.KING_BOMB, pokers, PokerLevel.LEVEL_SMALL_KING);
		}

		if (startIndex == endIndex) {
			if (levelTable[startIndex] == 1) {
				return new PokerSell(SellType.SINGLE, pokers, startIndex);
			} else if (levelTable[startIndex] == 2) {
				return new PokerSell(SellType.DOUBLE, pokers, startIndex);
			} else if (levelTable[startIndex] == 3) {
				return new PokerSell(SellType.THREE, pokers, startIndex);
			}
		}
		if (endIndex - startIndex == count - 1 && endIndex < PokerLevel.LEVEL_2) {
			if (levelTable[startIndex] == 1 && singleCount > 4 && doubleCount + threeCount + fourCount == 0) {
				return new PokerSell(SellType.SINGLE_STRAIGHT, pokers, endIndex);
			} else if (levelTable[startIndex] == 2 && doubleCount > 2 && singleCount + threeCount + fourCount == 0) {
				return new PokerSell(SellType.DOUBLE_STRAIGHT, pokers, endIndex);
			} else if (levelTable[startIndex] == 3 && threeCount > 1 && doubleCount + singleCount + fourCount == 0) {
				return new PokerSell(SellType.THREE_STRAIGHT, pokers, endIndex);
			} else if (levelTable[startIndex] == 4 && fourCount > 1 && doubleCount + threeCount + singleCount == 0) {
				return new PokerSell(SellType.FOUR_STRAIGHT, pokers, endIndex);
			}
		}

		if (threeCount != 0) {
			if (singleCount != 0 && singleCount == threeCount && doubleCount == 0 && fourCount == 0) {
				if (threeCount == 1) {
					return new PokerSell(SellType.THREE_ZONES_SINGLE, pokers, threeEndIndex);
				}
				if (threeEndIndex - threeStartIndex + 1 == threeCount && threeEndIndex < PokerLevel.LEVEL_2) {
					return new PokerSell(SellType.THREE_STRAIGHT_WITH_SINGLE, pokers, threeEndIndex);
				}
			} else if (doubleCount != 0 && doubleCount == threeCount && singleCount == 0 && fourCount == 0) {
				if (threeCount == 1) {
					return new PokerSell(SellType.THREE_ZONES_DOUBLE, pokers, threeEndIndex);
				}
				if (threeEndIndex - threeStartIndex + 1 == threeCount && threeEndIndex < PokerLevel.LEVEL_2) {
					return new PokerSell(SellType.THREE_STRAIGHT_WITH_DOUBLE, pokers, threeEndIndex);
				}
			} else if (singleCount + doubleCount * 2 == threeCount && fourCount == 0) {
				return new PokerSell(SellType.THREE_STRAIGHT_WITH_SINGLE, pokers, threeEndIndex);
			}
		}

		if (fourCount != 0) {
			if (singleCount != 0 && singleCount == fourCount * 2 && doubleCount == 0 && threeCount == 0) {
				if (fourCount == 1) {
					return new PokerSell(SellType.FOUR_ZONES_SINGLE, pokers, fourEndIndex);
				}
				if (fourEndIndex - fourStartIndex + 1 == fourCount && fourEndIndex < PokerLevel.LEVEL_2) {
					return new PokerSell(SellType.FOUR_STRAIGHT_WITH_SINGLE, pokers, fourEndIndex);
				}
			} else if (doubleCount != 0 && doubleCount == fourCount * 2 && singleCount == 0 && threeCount == 0) {
				if (fourCount == 1) {
					return new PokerSell(SellType.FOUR_ZONES_DOUBLE, pokers, fourEndIndex);
				}
				if (fourEndIndex - fourStartIndex + 1 == fourCount && fourEndIndex < PokerLevel.LEVEL_2) {
					return new PokerSell(SellType.FOUR_STRAIGHT_WITH_DOUBLE, pokers, fourEndIndex);
				}
			}
		}
		return new PokerSell(SellType.ILLEGAL, [], -1);
	}

	private static arrayPushAll(dest: Array<any>, src: Array<any>) {
		if (dest == undefined || src == undefined) {
			return;
		}

		src.forEach((data) => dest.push(data));
	}

	private static isContains(list: Array<any>, data: any): boolean {
		if (list == undefined || list.length == 0) {
			return false;
		}

		for (let val of list) {
			if (val == data) {
				return true;
			}
		}
		return false;
	}

	private static parsePokerSells(pokers: Array<Poker>): Array<PokerSell> {
		let pokerSells = [];
		let size = pokers.length;

		//all single or double
		{
			let count = 0;
			let lastLevel = -1;
			let sellPokers: Array<Poker> = new Array(4);
			for (let poker of pokers) {
				let level = poker.level;
				if (lastLevel == -1) {
					++count;
				} else {
					if (level == lastLevel) {
						++count;
					} else {
						count = 1;
						sellPokers = [];
					}
				}
				sellPokers.push(poker);
				if (count == 1) {
					pokerSells.push(new PokerSell(SellType.SINGLE, sellPokers, poker.level));
				} else if (count == 2) {
					pokerSells.push(new PokerSell(SellType.DOUBLE, sellPokers, poker.level));
				} else if (count == 3) {
					pokerSells.push(new PokerSell(SellType.THREE, sellPokers, poker.level));
				} else if (count == 4) {
					pokerSells.push(new PokerSell(SellType.BOMB, sellPokers, poker.level));
				}

				lastLevel = level;
			}
		}
		//Shunzi
		{
			PokerHelper.parsePokerSellStraight(pokerSells, SellType.SINGLE);
			PokerHelper.parsePokerSellStraight(pokerSells, SellType.DOUBLE);
			PokerHelper.parsePokerSellStraight(pokerSells, SellType.THREE);
			PokerHelper.parsePokerSellStraight(pokerSells, SellType.BOMB);
		}

		//Shunzi with args
		{
			for (let index = 0; index < pokerSells.length; index++) {
				let sell = pokerSells[index];
				if (sell.getSellType() == SellType.THREE) {
					PokerHelper.parseArgs(pokerSells, sell, 1, SellType.SINGLE, SellType.THREE_ZONES_SINGLE);
					PokerHelper.parseArgs(pokerSells, sell, 1, SellType.DOUBLE, SellType.THREE_ZONES_DOUBLE);
				} else if (sell.getSellType() == SellType.BOMB) {
					PokerHelper.parseArgs(pokerSells, sell, 2, SellType.SINGLE, SellType.FOUR_ZONES_SINGLE);
					PokerHelper.parseArgs(pokerSells, sell, 2, SellType.DOUBLE, SellType.FOUR_ZONES_DOUBLE);
				} else if (sell.getSellType() == SellType.THREE_STRAIGHT) {
					let count = sell.getSellPokers().size() / 3;
					PokerHelper.parseArgs(pokerSells, sell, count, SellType.SINGLE, SellType.THREE_STRAIGHT_WITH_SINGLE);
					PokerHelper.parseArgs(pokerSells, sell, count, SellType.DOUBLE, SellType.THREE_STRAIGHT_WITH_DOUBLE);
				} else if (sell.getSellType() == SellType.FOUR_STRAIGHT) {
					let count = (sell.getSellPokers().size() / 4) * 2;
					PokerHelper.parseArgs(pokerSells, sell, count, SellType.SINGLE, SellType.FOUR_STRAIGHT_WITH_SINGLE);
					PokerHelper.parseArgs(pokerSells, sell, count, SellType.DOUBLE, SellType.FOUR_STRAIGHT_WITH_DOUBLE);
				}
			}
		}

		//king boom
		{
			if (size > 1) {
				if (pokers[size - 1].level == PokerLevel.LEVEL_BIG_KING && pokers[size - 2].level == PokerLevel.LEVEL_SMALL_KING) {
					pokerSells.push(new PokerSell(SellType.KING_BOMB, [pokers[size - 2], pokers[size - 1]], PokerLevel.LEVEL_BIG_KING));
				}
			}
		}

		return pokerSells;
	}

	private static parseArgs(pokerSells: Array<PokerSell>, pokerSell: PokerSell, deep: number, sellType: SellType, targetSellType: SellType) {
		let existLevelSet: Set<number> = new Set();
		for (let p of pokerSell.getSellPokers()) {
			existLevelSet.add(p.level);
		}
		PokerHelper.parseArgsNext(existLevelSet, pokerSells, new Set([]), pokerSell, deep, sellType, targetSellType);
	}

	private static parseArgsNext(existLevelSet: Set<number>, pokerSells: Array<PokerSell>, pokersList: Set<Array<Poker>>, pokerSell: PokerSell, deep: number, sellType: SellType, targetSellType: SellType) {
		if (deep == 0) {
			let allPokers: Array<Poker> = [];
			PokerHelper.arrayPushAll(allPokers, pokerSell.getSellPokers());
			for (let ps of pokersList) {
				PokerHelper.arrayPushAll(allPokers, ps);
			}
			pokerSells.push(new PokerSell(targetSellType, allPokers, pokerSell.getCoreLevel()));
			return;
		}

		for (let index = 0; index < pokerSells.length; index++) {
			let subSell: PokerSell = pokerSells[index];
			if (subSell.getSellType() == sellType && !PokerHelper.isContains(Array.from(existLevelSet), subSell.getCoreLevel())) {
				pokersList.add(subSell.getSellPokers());
				existLevelSet.add(subSell.getCoreLevel());
				PokerHelper.parseArgsNext(existLevelSet, pokerSells, pokersList, pokerSell, deep - 1, sellType, targetSellType);
				existLevelSet.delete(subSell.getCoreLevel());
				pokersList.delete(subSell.getSellPokers());
			}
		}
	}

	private static parsePokerSellStraight(pokerSells: Array<PokerSell>, sellType: SellType) {
		let minLength = -1;
		let width = -1;
		let targetSellType: SellType = SellType.ILLEGAL;
		if (sellType == SellType.SINGLE) {
			minLength = 5;
			width = 1;
			targetSellType = SellType.SINGLE_STRAIGHT;
		} else if (sellType == SellType.DOUBLE) {
			minLength = 3;
			width = 2;
			targetSellType = SellType.DOUBLE_STRAIGHT;
		} else if (sellType == SellType.THREE) {
			minLength = 2;
			width = 3;
			targetSellType = SellType.THREE_STRAIGHT;
		} else if (sellType == SellType.BOMB) {
			minLength = 2;
			width = 4;
			targetSellType = SellType.FOUR_STRAIGHT;
		}

		let increase_1 = 0;
		let lastLevel_1 = -1;
		let sellPokers_1: Array<Poker> = new Array(4);
		for (let index = 0; index < pokerSells.length; index++) {
			let sell = pokerSells[index];

			if (sell.getSellType() != sellType) {
				continue;
			}
			let level = sell.getCoreLevel();
			if (lastLevel_1 == -1) {
				++increase_1;
			} else {
				if (level - 1 == lastLevel_1 && level != PokerLevel.LEVEL_2) {
					++increase_1;
				} else {
					PokerHelper.addPokers(pokerSells, minLength, width, targetSellType, increase_1, sellPokers_1);

					increase_1 = 1;
				}
			}
			PokerHelper.arrayPushAll(sellPokers_1, sell.getSellPokers());
			lastLevel_1 = level;
		}
		PokerHelper.addPokers(pokerSells, minLength, width, targetSellType, increase_1, sellPokers_1);
	}

	private static addPokers(pokerSells: Array<PokerSell>, minLenght: number, width: number, targetSellType: SellType, increase_1: number, sellPokers_1: Array<Poker>) {
		if (increase_1 >= minLenght) {
			for (let s = 0; s <= increase_1 - minLenght; s++) {
				let len = minLenght + s;
				for (let subIndex: number = 0; subIndex <= increase_1 - len; subIndex++) {
					let start = subIndex * width;
					let end = ((subIndex + len) * width) + 1;
					let pokers = sellPokers_1.slice(start, end);
					pokerSells.push(new PokerSell(targetSellType, pokers, pokers[pokers.length - 1].level));
				}
			}
		}
		sellPokers_1 = [];
	}

	public static parseScore(sellType: SellType, level: number) {
		if (sellType == SellType.BOMB) {
			return level * 4 + 999;
		} else if (sellType == SellType.KING_BOMB) {
			return 0x7fffffff;
		} else if (sellType == SellType.SINGLE || sellType == SellType.DOUBLE || sellType == SellType.THREE) {
			return level;
		} else if (sellType == SellType.SINGLE_STRAIGHT || sellType == SellType.DOUBLE_STRAIGHT || sellType == SellType.THREE_STRAIGHT || sellType == SellType.FOUR_STRAIGHT) {
			return level;
		} else if (sellType == SellType.THREE_ZONES_SINGLE || sellType == SellType.THREE_STRAIGHT_WITH_SINGLE || sellType == SellType.THREE_ZONES_DOUBLE || sellType == SellType.THREE_STRAIGHT_WITH_DOUBLE) {
			return level;
		} else if (sellType == SellType.FOUR_ZONES_SINGLE || sellType == SellType.FOUR_STRAIGHT_WITH_SINGLE || sellType == SellType.FOUR_ZONES_DOUBLE || sellType == SellType.FOUR_STRAIGHT_WITH_DOUBLE) {
			return level;
		}
		return -1;
	}

	private static findMinPokersGroup(pokers: Array<Poker>) {

		let pokerIndex: Map<number, Array<number>> = new Map();
		for (let i = 0; i < pokers.length; i++) {
			let poker = pokers[i];
			let indexList = pokerIndex.get(poker.level);
			if (indexList == undefined) {
				indexList = [];
			}
			indexList.push(i);
			pokerIndex.set(poker.level, indexList);
		}

		if (pokerIndex.size == 1) {
			let pokerSell = PokerHelper.checkPokerType(pokers);
			let positions: Array<number> = [];
			for (let i = 0; i < pokers.length; i++) {
				positions.push(i);
			}
			pokerSell.setPositions(positions);
			return pokerSell;
		}

		//获取第一个不同牌型的位置
		let diffIndex: Array<number> = [];
		let singleKey: Array<number> = [];
		let doubleKey: Array<number> = [];
		let threeKey: Array<number> = [];
		//		diffIndex.add(0);
		let minKey = -1;
		for (let k of pokerIndex.keys()) {
			let indexList: Array<number> = pokerIndex.get(k);
			diffIndex.push(indexList[0]);
			if (indexList.length == 1) {
				singleKey.push(k);
			} else if (indexList.length == 2) {
				doubleKey.push(k);
			} else if (indexList.length == 3) {
				threeKey.push(k);
			}

			if (minKey == -1) {
				minKey = k;
			}
		}
		// console.log("============> diffIndex: " + diffIndex);

		let futurePokers: Array<Poker> = [];
		let positions: Array<number> = [];

		if (pokerIndex.get(minKey).length == 2) {
			let poker0 = pokers[pokerIndex.get(minKey)[0]];
			let poker1 = pokers[pokerIndex.get(minKey)[1]];
			futurePokers.push(poker0);
			futurePokers.push(poker1);
			PokerHelper.arrayPushAll(positions, pokerIndex.get(minKey));
		} else if (pokerIndex.get(minKey).length == 3) {
			let poker0 = pokers[pokerIndex.get(minKey)[0]];
			let poker1 = pokers[pokerIndex.get(minKey)[1]];
			let poker2 = pokers[pokerIndex.get(minKey)[2]];
			futurePokers.push(poker0);
			futurePokers.push(poker1);
			futurePokers.push(poker2);
			PokerHelper.arrayPushAll(positions, pokerIndex.get(minKey));
			if (singleKey.length > 0) {
				let key = singleKey[0];
				let poker = pokers[pokerIndex.get(key)[0]];
				futurePokers.push(poker);
				positions.push(pokerIndex.get(key)[0]);
			} else if (doubleKey.length > 0) {
				let key = doubleKey[0];
				let poker = pokers[pokerIndex.get(key)[0]];
				let poker1 = pokers[pokerIndex.get(key)[1]];
				futurePokers.push(poker);
				futurePokers.push(poker1);
				PokerHelper.arrayPushAll(positions, pokerIndex.get(key));
			}
		} else {
			if (minKey == PokerLevel.LEVEL_SMALL_KING && pokerIndex.size == 2) {
				//王炸
				for (let key of pokerIndex.keys()) {
					let poker = pokers[pokerIndex.get(key)[0]];
					futurePokers.push(poker);
					positions.push(pokerIndex.get(key)[0]);
				}
			} else {
				//单张
				let poker = pokers[pokerIndex.get(minKey)[0]];
				futurePokers.push(poker);
				positions.push(pokerIndex.get(minKey)[0]);
			}
		}

		let pokerSell = PokerHelper.checkPokerType(futurePokers);
		pokerSell.setPositions(positions);
		return pokerSell;
	}

	private static findAllBiggerPokerType3P(pokers: Array<Poker>, pokerSell: PokerSell) {

		let res: Array<PokerSell> = [];
		let bombs: Array<PokerSell> = PokerHelper.findBombPokerType3P(pokers, pokerSell);
		if (!PokerHelper.isBomb(pokerSell.getSellType())) {
			let generals = PokerHelper.findGeneralPokerType3P(pokers, pokerSell);
			if (SellType.SINGLE == pokerSell.getSellType()) {
				PokerHelper.arrayPushAll(res, generals.sort(function (A, B) {
					return A.getSellType() - B.getSellType();
				}));
			} else {
				PokerHelper.arrayPushAll(res, generals);
			}
			PokerHelper.arrayPushAll(res, bombs);
			return res;
		} else {
			return bombs;
		}
	}

	private static findGeneralPokerType3P(pokers: Array<Poker>, pokerSell: PokerSell) {
		return PokerHelper.findPokersByPokerType(pokers, pokerSell);
	}

	private static findBombPokerType3P(pokers: Array<Poker>, pokerSell: PokerSell) {
		let bombs: Array<PokerSell> = PokerHelper.findAllBombPokers(pokers);
		//如果不是炸弹，那所有的炸弹都要返回
		if (!PokerHelper.isBomb(pokerSell.getSellType())) {
			return bombs;
		} else {//如果是炸弹，就要保留大的炸弹
			let bigBombs = [];
			bombs.forEach((bomb) => {
				if (bomb.getScore() > pokerSell.getScore()) {
					bigBombs.push(bomb);
				}
			});
			return bigBombs;
		}
	}

	private static findAllBombPokers(pokers: Array<Poker>): Array<PokerSell> {
		let res: Array<PokerSell> = [];

		let pokerIndex: Map<number, Array<number>> = new Map();
		for (let i = 0; i < pokers.length; i++) {
			let poker = pokers[i];
			let indexList = pokerIndex.get(poker.level);
			if (indexList == undefined) {
				indexList = [];
			}
			indexList.push(i);
			pokerIndex.set(poker.level, indexList);
		}
		// console.log("============> pokerIndex: " + pokerIndex);

		for (let indexList of pokerIndex.values()) {
			if (indexList.length >= 4) {
				let futureSell = [];
				for (let i of indexList) {
					futureSell.push(pokers[i]);
				}
				let type = PokerHelper.checkPokerType(futureSell);
				type.setPositions(indexList);
				res.push(type);
			} else if (PokerHelper.isContains(Array.from(pokerIndex).map(item => item[0]), PokerLevel.LEVEL_SMALL_KING) && PokerHelper.isContains(Array.from(pokerIndex).map(item => item[0]), PokerLevel.LEVEL_BIG_KING)) {
				let futureSell = [];
				futureSell.push(pokers[pokerIndex.get(PokerLevel.LEVEL_SMALL_KING)[0]]);
				futureSell.push(pokers[pokerIndex.get(PokerLevel.LEVEL_BIG_KING)[0]]);
				let type = PokerHelper.checkPokerType(futureSell);
				let indexs = [];
				indexs.push(pokerIndex.get(PokerLevel.LEVEL_SMALL_KING)[0]);
				indexs.push(pokerIndex.get(PokerLevel.LEVEL_BIG_KING)[0]);
				type.setPositions(indexs);
				res.push(type);
			}
		}
		return res;
	}

	/**
 * 找到指定类型的牌
 * @param pokers
 * @param pokerSell
 * @return List<PokerSell> 返回满足的类型
 */
	private static findPokersByPokerType(pokers: Array<Poker>, pokerSell: PokerSell): Array<PokerSell> {
		let pokerIndex: Map<number, Array<number>> = new Map();
		for (let i = 0; i < pokers.length; i++) {
			let poker = pokers[i];
			let indexList = pokerIndex.get(poker.level);
			if (indexList == undefined) {
				indexList = [];
			}
			indexList.push(i);
			pokerIndex.set(poker.level, indexList);
		}
		// console.log("============> pokerIndex: " + pokerIndex);
		//获取第一个不同牌型的位置
		let diffIndex: Array<number> = [];
		//		diffIndex.push(0);
		for (let data of pokerIndex) {
			let key = data[0];
			let indexList = data[1];
			diffIndex.push(indexList[0]);
		}


		// console.log("============> diffIndex: " + diffIndex);
		let res: Array<PokerSell> = [];
		switch (pokerSell.getSellType()) {
			case SellType.SINGLE:
				for (let i = 0; i < pokers.length; i++) {
					let poker = pokers[i];
					let futureType = PokerHelper.checkPokerType([poker]);
					if (pokerSell.getSellType() == futureType.getSellType() && futureType.getScore() > pokerSell.getScore()) {
						futureType.setPositions([i]);
						res.push(futureType);
					}
				}
				break;
			case SellType.DOUBLE:
				for (let i = 0; i < diffIndex.length; i++) {
					let poker = pokers[diffIndex[i]];
					let count = pokerIndex.get(poker.level).length;
					if (count < 2) {
						continue;
					}

					let index = diffIndex[i];
					if (pokers.length < index + 1) {
						continue;
					}

					let poker1 = pokers[index];
					let poker2 = pokers[index + 1];
					let futureType = PokerHelper.checkPokerType([poker1, poker2]);

					if (pokerSell.getSellType() == futureType.getSellType() && futureType.getScore() > pokerSell.getScore()) {
						futureType.setPositions([index, index + 1]);
						res.push(futureType);
					}
				}
				break;
			case SellType.THREE:
				for (let i = 0; i < diffIndex.length; i++) {
					let poker = pokers[diffIndex[i]];
					let count = pokerIndex.get(poker.level).length;
					if (count < 3) {
						continue;
					}
					let index = diffIndex[i];
					let poker1 = pokers[index];
					let poker2 = pokers[index + 1];
					let poker3 = pokers[index + 2];
					let futureType = PokerHelper.checkPokerType([poker1, poker2, poker3]);
					if (pokerSell.getSellType() == futureType.getSellType() && futureType.getScore() > pokerSell.getScore()) {
						futureType.setPositions([index, index + 1, index + 2]);
						res.push(futureType);
					}
				}
				break;
			case SellType.THREE_ZONES_SINGLE:
				if (diffIndex.length < 2) {
					break;
				}
				for (let i = 0; i < diffIndex.length; i++) {
					let poker = pokers[diffIndex[i]];
					let count = pokerIndex.get(poker.level).length;
					if (count < 3) {
						continue;
					}
					let index = diffIndex[i];
					let poker1 = pokers[index];
					let poker2 = pokers[index + 1];
					let poker3 = pokers[index + 2];

					// console.log("============> THREE_ZONES_SINGLE: " + count + " " +index);

					for (let j = 0; j < diffIndex.length; j++) {
						let pokerJ = pokers[diffIndex[j]];
						if (pokerJ.level == poker.level) {
							continue;
						}

						let futurePokers = [poker1, poker2, poker3];
						let positions = [index, index + 1, index + 2];
						futurePokers.push(pokerJ);
						positions.push(diffIndex[j]);
						let futureType = PokerHelper.checkPokerType(futurePokers);
						// console.log("============> futureType: " + futureType.getSellType() + " " +j);
						if (pokerSell.getSellType() == futureType.getSellType() && futureType.getScore() > pokerSell.getScore()) {
							futureType.setPositions(positions);
							res.push(futureType);
						}
					}
				}

				break;
			case SellType.THREE_ZONES_DOUBLE:
				let hasTwo: Array<number> = [];
				let hasThree: Array<number> = [];

				for (let data of pokerIndex) {
					if (data[1].length >= 3) {
						hasThree.push(data[0]);
					} else if (data[1].length >= 2) {
						hasTwo.push(data[0]);
					}
				}

				if (hasTwo.length <= 0 || hasTwo.length != hasThree.length) {
					break;
				}

				hasThree.forEach((level) => {
					hasTwo.forEach((tow) => {
						let threeIndexList = pokerIndex[level];
						let futurePokers = [pokers[threeIndexList[0]], pokers[threeIndexList[1]], pokers[threeIndexList[2]]];
						let twoIndexList = pokerIndex[tow];
						futurePokers.push(pokers[twoIndexList[0]]);
						futurePokers.push(pokers[twoIndexList[1]]);
						let futureSell = PokerHelper.checkPokerType(futurePokers);
						if (pokerSell.getSellType() == futureSell.getSellType() && futureSell.getScore() > pokerSell.getScore()) {
							futureSell.addPositions([threeIndexList[0], threeIndexList[1], threeIndexList[2]]);
							futureSell.addPositions([twoIndexList[0], twoIndexList[1]]);
							res.push(futureSell);
						}
					});
				});

				break;

			case SellType.SINGLE_STRAIGHT:
				let ss_count = pokerSell.getSellPokers().length;
				if (pokerIndex.size < ss_count) {
					break;
				}
				pokerSell.getSellPokers().sort(function (A, B) {
					return A.level - B.level;
				});
				// console.log("============> pokerSell: " + pokerSell.getSellPokers());
				let minLevel = pokerSell.getSellPokers()[0].level;
				let sortIndex: Map<number, Array<number>> = new Map();
				pokerIndex.forEach((data) => {
					let level = data[0];
					if (level <= minLevel || level > PokerLevel.LEVEL_A) {
						;
					} else {
						sortIndex.set(level, pokerIndex[level]);
					}

				});

				if (sortIndex.size < ss_count) {
					break;
				}
				// console.log("============> sortIndex: " + sortIndex);

				let link_count = 0;
				let start_key = 0;
				let last_key_index = 0;
				let last_key = 0;
				for (let data of sortIndex) {
					let key = data[0];
					last_key_index++;
					if (last_key == 0) {
						link_count = 1;
						last_key = key;
						start_key = key;
					} else if (last_key + 1 == key) {
						link_count++;
						last_key = key;
					} else {
						if (link_count >= ss_count) {
							last_key = key;
							break;
						}

						link_count = 1;
						last_key = key;
						start_key = key;
					}
					// console.log("============> start_key:" + start_key + " last_key:"+last_key + " link_count:" + link_count);
				}

				// console.log("============> ss_count: " + ss_count + " link_count:" + link_count+ " start key: " + start_key);
				if (link_count >= ss_count) {
					let num = link_count - ss_count + 1;
					for (let i = 0; i < num; i++) {
						let futurePokers = [];
						let positions = [];
						for (let k = 0; k < ss_count; k++) {
							let key = start_key + i + k;
							let index = pokerIndex.get(key)[0];
							let poker = pokers[index];
							futurePokers.push(poker);
							positions.push(index);
						}

						let futureSell = PokerHelper.checkPokerType(futurePokers);
						// console.log("============> futurePokers: " + futurePokers + " getSellType: " + futureSell.getSellType());
						if (pokerSell.getSellType() == futureSell.getSellType() && futureSell.getScore() > pokerSell.getScore()) {
							futureSell.setPositions(positions);
							res.push(futureSell);
						}
					}
				}

				// console.log("============> sortIndex size: " + sortIndex.size + " last_key_index:" + last_key_index);
				if ((sortIndex.size - last_key_index) >= ss_count) {
					link_count = 0;
					start_key = last_key;
					last_key = 0;
					for (let data of sortIndex) {
						let key = data[0];
						if (key < start_key) {
							continue;
						}

						if (last_key == 0) {
							link_count = 1;
							last_key = key;
							start_key = key;
						} else if (last_key + 1 == key) {
							link_count++;
							last_key = key;
						} else {
							if (link_count >= ss_count) {
								last_key = key;
								break;
							}

							last_key = 0;
						}
					}

					// console.log("============> ss_count: " + ss_count + " link_count:" + link_count+" start key:" + start_key);
					if (link_count >= ss_count) {
						let num = link_count - ss_count + 1;
						for (let i = 0; i < num; i++) {
							let futurePokers = [];
							let positions = [];
							for (let k = 0; k < ss_count; k++) {
								let key = start_key + i + k;
								let index = pokerIndex.get(key)[0];
								let poker = pokers[index];
								futurePokers.push(poker);
								positions.push(index);
							}

							let futureSell = PokerHelper.checkPokerType(futurePokers);
							if (pokerSell.getSellType() == futureSell.getSellType() && futureSell.getScore() > pokerSell.getScore()) {
								futureSell.setPositions(positions);
								res.push(futureSell);
							}
						}
					}
				}

				break;
			case SellType.DOUBLE_STRAIGHT:
				//几连对
				let straightCount = pokerSell.getStraightCount();
				for (let i = 0; i < diffIndex.length; i++) {
					let index = diffIndex[i];
					let poker = pokers[index];
					let level = poker.level;
					if (level < 3 || level > 14 - straightCount + 1) { //2和大小王不够成连对
						continue;
					}
					let futurePokers = [];
					let positions = [];
					for (let startLevel = level; startLevel < level + straightCount; startLevel++) {
						let indexList = pokerIndex.get(startLevel);
						if (indexList.length < 2) {
							break;
						}
						let poker1 = pokers[indexList[0]];
						let poker2 = pokers[indexList[1]];
						futurePokers.push(poker1);
						futurePokers.push(poker2);
						positions.push(indexList[0]);
						positions.push(indexList[1]);
					}
					if (futurePokers.length < straightCount * 2) {
						continue;
					}
					let futureSell = PokerHelper.checkPokerType(futurePokers);
					if (pokerSell.getSellType() == futureSell.getSellType() && futureSell.getScore() > pokerSell.getScore()) {
						futureSell.setPositions(positions);
						res.push(futureSell);
					}
				}
				break;
			case SellType.THREE_STRAIGHT:
				//几连飞机
				let sc = pokerSell.getStraightCount();
				for (let i = 0; i < diffIndex.length; i++) {
					let index = diffIndex[i];
					let poker = pokers[index];
					let level = poker.level;
					if (level < 3 || level > 14 - sc + 1) { //2和大小王不够成连对
						continue;
					}
					let futurePokers = [];
					let positions = [];
					for (let startLevel = level; startLevel < level + sc; startLevel++) {
						let indexList = pokerIndex.get(startLevel);
						if (indexList.length < 3) {
							break;
						}
						let poker1 = pokers[indexList[0]];
						let poker2 = pokers[indexList[1]];
						let poker3 = pokers[indexList[2]];
						futurePokers.push(poker1);
						futurePokers.push(poker2);
						futurePokers.push(poker3);
						positions.push(indexList[0]);
						positions.push(indexList[1]);
						positions.push(indexList[2]);
					}
					if (futurePokers.length < sc * 3) {
						continue;
					}
					let futureSell = PokerHelper.checkPokerType(futurePokers);
					if (pokerSell.getSellType() == futureSell.getSellType() && futureSell.getScore() > pokerSell.getScore()) {
						futureSell.setPositions(positions);
						res.push(futureSell);
					}
				}
				break;
			case SellType.THREE_STRAIGHT_WITH_DOUBLE:
				let hasDouble: Array<number> = [];
				let hasTriple: Array<number> = [];

				for (let data of pokerIndex) {
					if (data[1].length >= 3) {
						hasTriple.push(data[0]);
						hasDouble.push(data[0]);
					} else if (data[1].length >= 2) {
						hasDouble.push(data[0]);
					}
				}

				if (hasDouble.length <= 0 || hasDouble.length != hasDouble.length) {
					break;
				}

				let sCount = pokerSell.getStraightCount();

				//获取翅膀的所有组合
				let two: Array<Set<number>> = [];
				hasDouble.forEach((data) => {
					hasDouble.forEach((value) => {
						if (data != value) {
							let ss: Set<number> = new Set();
							ss.add(data);
							ss.add(value);
							two.push(ss);
						}
					});
				});

				//去重
				let combinations = new Set(two);

				//飞机需要连续
				for (let th = 0; th < hasTriple.length - sCount + 1; th++) {
					let futurePokers = [];
					let positions = [];
					for (let startLevel = th; startLevel < th + sCount; startLevel++) {
						let indexList = pokerIndex.get(startLevel);
						let poker1 = pokers[indexList[0]];
						let poker2 = pokers[indexList[1]];
						let poker3 = pokers[indexList[2]];
						futurePokers.push(poker1);
						futurePokers.push(poker2);
						futurePokers.push(poker3);
						positions.push(indexList[0]);
						positions.push(indexList[1]);
						positions.push(indexList[2]);
					}

					for (let combination of combinations) {
						let poker1 = pokers[pokerIndex.get(combination[0])[0]]
						let poker2 = pokers[pokerIndex.get(combination[0])[1]]
						let poker3 = pokers[pokerIndex.get(combination[1])[0]]
						let poker4 = pokers[pokerIndex.get(combination[1])[1]]
						futurePokers.push(poker1);
						futurePokers.push(poker2);
						futurePokers.push(poker3);
						futurePokers.push(poker4);
						positions.push(pokerIndex.get(combination[0])[0]);
					}

					let futureSell = PokerHelper.checkPokerType(futurePokers);
					if (pokerSell.getSellType() == futureSell.getSellType() && futureSell.getScore() > pokerSell.getScore()) {
						futureSell.addPositions(positions);
						res.push(futureSell);
					}
				}

				break;
			case SellType.BOMB:
				for (let data of pokerIndex) {
					let level = data[0];
					let indexList = data[1];
					if (indexList.length >= 4) {
						let futurePokers = [];
						indexList.forEach((index) => { futurePokers.push(pokers[index]) });
						let futureSell = PokerHelper.checkPokerType(futurePokers);
						if (futureSell.getScore() > pokerSell.getScore()) {
							futureSell.setPositions(indexList);
							res.push(futureSell);
						}
					}
				}

			//            case KING_BOMB: 王炸就是要不起
			default:
				break;
		}
		return res;
	}

	public static parseStraightCount(pokers: Array<Poker>, sellType: SellType): number {
		let count = -1;
		let singleCount = 0;
		let doubleCount = 0;
		if (null == pokers || pokers.length <= 0) {
			return count;
		}

		let pokerArray = new Array(18);
		for (let i = 0; i < pokerArray.length; i++) {
			pokerArray[i] = 0;
		}

		for (let poker of pokers) {
			pokerArray[poker.level] += 1;
		}

		for (let i = PokerLevel.LEVEL_3; i < PokerLevel.LEVEL_2; i++) {
			if (pokerArray[i] == 1) {
				singleCount++;
			} else if (pokerArray[i] == 2) {
				doubleCount++;
			}
		}

		switch (sellType) {
			case SellType.SINGLE:
			case SellType.DOUBLE:
			case SellType.THREE:
			case SellType.KING_BOMB:
			case SellType.THREE_ZONES_SINGLE:
			case SellType.THREE_ZONES_DOUBLE:
			case SellType.FOUR_ZONES_SINGLE:
			case SellType.FOUR_ZONES_DOUBLE:
				count = 1;
				break;
			case SellType.SINGLE_STRAIGHT:
				count = pokers.length;
				break;
			case SellType.DOUBLE_STRAIGHT:
				count = pokers.length / 2;
				break;
			case SellType.THREE_STRAIGHT:
				count = pokers.length / 3;
				break;
			case SellType.BOMB:
			case SellType.FOUR_STRAIGHT:
				count = pokers.length / 4;
				break;
			case SellType.THREE_STRAIGHT_WITH_SINGLE:
				count = singleCount;
				break;
			case SellType.THREE_STRAIGHT_WITH_DOUBLE:
				count = doubleCount;
				break;
			case SellType.FOUR_STRAIGHT_WITH_SINGLE:
				count = singleCount;
				break;
			case SellType.FOUR_STRAIGHT_WITH_DOUBLE:
				count = doubleCount;
				break;
			default:
				break;
		}

		return count;
	}

	static pokerArray: Array<number> = new Array(18);
	static bigCards: Array<Poker> = new Array();
	static allPokerMap: Map<number, Array<Poker>> = new Map();
	static allPositionMap: Map<String, number> = new Map();
	static groups: Array<PokerGroup> = new Array();
	public static gLeftMinTimes: number = 0;  //该轮拆牌后剩余手数

	private static clearn() {
		PokerHelper.gLeftMinTimes = 0;
		PokerHelper.allPokerMap.clear();
		PokerHelper.allPositionMap.clear();
		PokerHelper.bigCards = [];
		PokerHelper.groups = [];
		for (let i = 0; i < PokerHelper.pokerArray.length; i++) {
			PokerHelper.pokerArray[i] = 0;
		}
	}

	private static findAllBigSellType(pokers: Array<Poker>, lastPokerSell: PokerSell): Array<PokerSell> {
		let listPokers = [];
		PokerHelper.arrayPushAll(listPokers, pokers);
		PokerHelper.splitHandPoker(listPokers);

		let resSells: Array<PokerSell> = new Array();
		let firstLevel = lastPokerSell.getCoreLevel();
		let straightCount = lastPokerSell.getStraightCount() == -1 ? 0 : lastPokerSell.getStraightCount(); //连对是几对，顺子是几顺

		for (let grp of PokerHelper.groups) {
			// console.log("******************************************************************");
			// console.log("========> times:" + grp.getTimes() + " weight: " + grp.getWeight());
			// console.log("========> firstLevel:" + firstLevel + " straightCount: " + straightCount);

			switch (lastPokerSell.getSellType()) {
				case SellType.SINGLE:
					if (grp.single.length > 0) {
						let res: Array<Poker> = [];
						grp.single.forEach(poker => {
							if (poker.level > firstLevel) {
								res.push(poker);
							}
						});
						PokerHelper.printPokers("单张小牌res：", res);
						if (res.length > 0) {
							for (let re of res) {
								let sell: PokerSell = new PokerSell(SellType.SINGLE, new Array(re), re.level);
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(re));
								sell.setPositions([position]);
								resSells.push(sell);
							}
						}
					}

					if (grp.singleBig.length > 0) {
						let res: Array<Poker> = [];
						grp.singleBig.forEach(poker => {
							if (poker.level > firstLevel) {
								res.push(poker);
							}
						});

						PokerHelper.printPokers("单张大牌res：", res);
						if (res.length > 0) {
							for (let re of res) {
								let sell: PokerSell = new PokerSell(SellType.SINGLE, [re], re.level);
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(re));
								sell.setPositions([position]);
								resSells.push(sell);
							}
						}
					}
					break;
				case SellType.DOUBLE:
					if (grp.two.length > 0) {
						let res: Array<Array<Poker>> = [];
						grp.two.forEach(poker => {
							if (poker[0].level > firstLevel) {
								res.push(poker);
							}
						});

						for (let re of res) {
							PokerHelper.printPokers("对子res：", re);
							let sell: PokerSell = new PokerSell(SellType.DOUBLE, re, re[0].level);
							let positions = [];
							for (let poker of re) {
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							sell.setPositions(positions);
							resSells.push(sell);
						}
					}

					//检查是否有对2
					if (firstLevel < PokerLevel.LEVEL_2 && grp.singleBig.length >= 2) {
						let res: Array<Poker> = [];
						grp.singleBig.forEach(poker => {
							if (poker.level == PokerLevel.LEVEL_2) {
								res.push(poker);
							}
						});
						if (res.length >= 2) {
							let sell: PokerSell = new PokerSell(SellType.DOUBLE, res.slice(0, 2), res[0].level);
							let positions = [];
							for (let i = 0; i < 2; i++) {
								let poker: Poker = res[i];
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							sell.setPositions(positions);
							resSells.push(sell);
						}
					}
					break;
				case SellType.THREE:
					if (grp.three.length > 0) {
						let res: Array<Array<Poker>> = [];
						grp.three.forEach(poker => {
							if (poker[0].level > firstLevel) {
								res.push(poker);
							}
						});
						for (let re of res) {
							PokerHelper.printPokers("对子res：", re);
							let sell: PokerSell = new PokerSell(SellType.THREE, re, re[0].level);
							let positions = [];
							for (let poker of re) {
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							sell.setPositions(positions);
							resSells.push(sell);
						}
					}
					//检查是否有三个2
					if (firstLevel < PokerLevel.LEVEL_2 && grp.singleBig.length >= 3) {
						let res: Array<Poker> = [];
						grp.singleBig.forEach(poker => {
							if (poker.level == PokerLevel.LEVEL_2) {
								res.push(poker);
							}
						});
						if (res.length >= 3) {
							let sell: PokerSell = new PokerSell(SellType.DOUBLE, res.slice(0, 3), res[0].level);
							let positions = [];
							for (let i = 0; i < 3; i++) {
								let poker: Poker = res[i];
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							sell.setPositions(positions);
							resSells.push(sell);
						}
					}
					break;
				case SellType.THREE_ZONES_SINGLE:
					if (grp.three.length > 0 && grp.single.length > 0) {
						let res: Array<Array<Poker>> = [];
						grp.three.forEach(poker => {
							if (poker[0].level > firstLevel) {
								res.push(poker);
							}
						});
						for (let re of res) {
							PokerHelper.printPokers("3带1res：", re);
							for (let pk of grp.single) {
								let pks: Array<Poker> = [];
								PokerHelper.arrayPushAll(pks, re);
								pks.push(pk);
								// PokerHelper.printPokers("--3带1res：", pks);

								let sell: PokerSell = new PokerSell(SellType.THREE_ZONES_SINGLE, pks, pks[0].level);
								let positions = [];
								for (let poker of pks) {
									let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
									positions.push(position);
								}
								sell.setPositions(positions);
								resSells.push(sell);
							}
						}
					}
					break;
				case SellType.THREE_ZONES_DOUBLE:
					if (grp.three.length > 0 && grp.two.length > 0) {
						let res: Array<Array<Poker>> = [];
						grp.three.forEach(poker => {
							if (poker[0].level > firstLevel) {
								res.push(poker);
							}
						});
						for (let re of res) {
							PokerHelper.printPokers("3带2res：", re);
							for (let pk of grp.two) {
								let pks: Array<Poker> = [];
								PokerHelper.arrayPushAll(pks, re);
								PokerHelper.arrayPushAll(pks, pk);

								let sell: PokerSell = new PokerSell(SellType.THREE_ZONES_DOUBLE, pks, pks[0].level);
								let positions = [];
								for (let poker of pks) {
									let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
									positions.push(position);
								}
								sell.setPositions(positions);
								resSells.push(sell);
							}
						}
					}
					break;
				case SellType.SINGLE_STRAIGHT:
					if (grp.shunzi.length > 0) {
						// SimplePrinter.serverLog("========> shunzi s:" + grp.getShunzi().size() + " 0 size: " + grp.getShunzi().get(0).size());
						let res: Array<Array<Poker>> = [];
						grp.three.forEach(poker => {
							if (poker[0].level > firstLevel && poker.length >= straightCount) {
								res.push(poker);
							}
						});
						for (let re of res) {
							PokerHelper.printPokers("顺子res：", re);
							let sell: PokerSell = new PokerSell(SellType.SINGLE_STRAIGHT, re, re[0].level);
							let positions = [];
							for (let poker of re) {
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							sell.setPositions(positions);
							resSells.push(sell);
						}
					}
					break;
				case SellType.DOUBLE_STRAIGHT:
					if (grp.liandui.length > 0) {
						let res: Array<Array<Poker>> = [];
						grp.liandui.forEach(poker => {
							if (poker[0].level > firstLevel && poker.length >= straightCount) {
								res.push(poker);
							}
						});
						for (let re of res) {
							PokerHelper.printPokers("连对res：", re);
							let sell: PokerSell = new PokerSell(SellType.DOUBLE_STRAIGHT, re, re[0].level);
							let positions = [];
							for (let poker of re) {
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							sell.setPositions(positions);
							resSells.push(sell);
						}
					}
					break;
				case SellType.THREE_STRAIGHT:
				case SellType.THREE_STRAIGHT_WITH_SINGLE:
				case SellType.THREE_STRAIGHT_WITH_DOUBLE:
					let sell: PokerSell = PokerHelper.findFlyPokerSell(lastPokerSell);
					if (sell != null) {
						let positions = [];
						for (let poker of sell.getSellPokers()) {
							let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
							positions.push(position);
						}
						sell.setPositions(positions);
						resSells.push(sell);
					}
					break;
				case SellType.BOMB:
					if (grp.bombs.length > 0) {
						let res: Array<Array<Poker>> = [];
						grp.bombs.forEach(poker => {
							if (poker[0].level > firstLevel) {
								res.push(poker);
							}
						});
						for (let re of res) {
							PokerHelper.printPokers("炸弹res：", re);
							let sellType = SellType.BOMB;
							if (re[0].level == PokerLevel.LEVEL_BIG_KING || re[0].level == PokerLevel.LEVEL_SMALL_KING) {
								sellType = SellType.KING_BOMB;
							}

							let ps: PokerSell = new PokerSell(sellType, re, re[0].level);
							let positions = [];
							for (let poker of re) {
								let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
								positions.push(position);
							}
							ps.setPositions(positions);
							resSells.push(ps);
						}
					}
					break;
				//            case KING_BOMB: 王炸就是要不起
				default:
					break;
			}

		}

		resSells.sort(function (A, B) {
			return A.coreLevel - B.coreLevel;
		});

		if (!PokerHelper.isBomb(lastPokerSell.getSellType())) {
			for (let grp of PokerHelper.groups) {
				//取炸弹
				for (let bombs of grp.bombs) {
					let sellType = SellType.BOMB;
					if (bombs[0].level == PokerLevel.LEVEL_BIG_KING || bombs[0].level == PokerLevel.LEVEL_SMALL_KING) {
						sellType = SellType.KING_BOMB;
					}

					let ps = new PokerSell(sellType, bombs, bombs[0].level);
					let positions = [];
					for (let poker of bombs) {
						let position = PokerHelper.allPositionMap.get(PokerHelper.alisName(poker));
						positions.push(position);
					}
					ps.setPositions(positions);
					resSells.push(ps);
				}
			}
		}

		//去重处理
		let newSells: Array<PokerSell> = [];
		if (resSells.length > 1) {
			let reps: Array<number> = [];
			for (let pokerSell of resSells) {
				let value = 0;
				for (let poker of pokerSell.getSellPokers()) {
					value += poker.level;
				}

				if (reps.indexOf(value) < 0) {
					reps.push(value);
					newSells.push(pokerSell);
				}
			}
		}

		// SimplePrinter.serverLog("============> sell size: " + newSells.size());
		// for (let pokerSell:PokerSell of newSells) {
		// 	PokerHelper.printPokers("可选出牌：", pokerSell.getSellPokers());
		// }

		if (newSells.length > 0) {
			return newSells;
		}
		return resSells;
	}

	public static splitHandPoker(pokers: Array<Poker>) {

		PokerHelper.clearn();

		for (let i = 0; i < pokers.length; i++) {
			PokerHelper.allPositionMap.set(PokerHelper.alisName(pokers[i]), i);
		}

		pokers.sort(function (A, B) {
			return A.level - B.level;
		});

		// console.log("********* > ", pokers);
		for (let poker of pokers) {
			if (poker.level < 0) {
				continue;
			}
			let pokerList = PokerHelper.allPokerMap.get(poker.level);
			if (!pokerList) {
				pokerList = new Array();
			}
			pokerList.push(poker);
			// console.log("********* > ", poker.level, pokerList);
			PokerHelper.allPokerMap.set(poker.level, pokerList);

			//            if (poker.getLevel().getLevel() >= PokerLevel.LEVEL_2.getLevel()) {
			//                bigPokers.add(poker);
			//                continue;
			//            }

			if (poker.level < PokerHelper.pokerArray.length) {
				PokerHelper.pokerArray[poker.level]++;
			}
		}

		// console.log("---------> ", PokerHelper.pokerArray);

		let kingBomb: Array<number> = [];         //王炸
		let bombLevelGroups: Array<number> = [];  //所有的炸弹组(不含王炸)
		let bigLevelGroups: Array<number> = [];   //2和单个大小王
		//1.找所有的炸弹
		if (PokerHelper.pokerArray[PokerLevel.LEVEL_SMALL_KING] != 0 && PokerHelper.pokerArray[PokerLevel.LEVEL_BIG_KING] != 0) {
			//王炸
			kingBomb.push(PokerLevel.LEVEL_SMALL_KING);
			kingBomb.push(PokerLevel.LEVEL_BIG_KING);
			PokerHelper.pokerArray[PokerLevel.LEVEL_SMALL_KING] = 0;
			PokerHelper.pokerArray[PokerLevel.LEVEL_BIG_KING] = 0;
		}

		// SimplePrinter.serverLog("============> pokerInt.length: " + pokerArray.length + " random: " + (new Random()).nextInt(3));

		//找大牌：2和单张大小王
		for (let i = PokerLevel.LEVEL_3; i < PokerHelper.pokerArray.length; i++) {
			if (PokerHelper.pokerArray[i] <= 0) {
				continue;
			}

			if (PokerHelper.pokerArray[i] >= 4) {
				bombLevelGroups.push(i);
				PokerHelper.pokerArray[i] = 0;
			} else if (i >= PokerLevel.LEVEL_2) {
				//找2和大小王
				bigLevelGroups.push(i);
				PokerHelper.pokerArray[i] = 0;
			}
		}

		//		printPokers(pokerArray);

		//[方案1]
		let group = PokerHelper.strategyThreeFirst(kingBomb, bombLevelGroups, bigLevelGroups);
		PokerHelper.groups.push(group);
		group = PokerHelper.strategyThreeAndTwoFirst(kingBomb, bombLevelGroups, bigLevelGroups);
		PokerHelper.groups.push(group);
		group = PokerHelper.strategyShunZiFirst(kingBomb, bombLevelGroups, bigLevelGroups);
		PokerHelper.groups.push(group);
		group = PokerHelper.strategyTwoFirst(kingBomb, bombLevelGroups, bigLevelGroups);
		PokerHelper.groups.push(group);

		PokerHelper.groups.sort(function (A, B) {
			return A.getTimes() - B.getTimes();
		});
	}

	//[方案1]
	//1.找所有的3个
	//2.找最长顺子
	//3.找所有顺子
	//4.找所有的对子
	//5.单张
	private static strategyThreeFirst(kingBomb: Array<number>, bombLevelGroups: Array<number>, bigLevelGroups: Array<number>): PokerGroup {
		let leftLevels = [];
		PokerHelper.arrayPushAll(leftLevels, PokerHelper.pokerArray);

		let pokerGroup = new PokerGroup();
		pokerGroup = PokerHelper.findThreeGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllShunZiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllLianDuiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllTwoGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllSingleGroups(pokerGroup, leftLevels);
		PokerHelper.checkLeftPokers(pokerGroup, leftLevels);

		pokerGroup = PokerHelper.addAllBigGroups(pokerGroup, kingBomb, bombLevelGroups, bigLevelGroups);
		pokerGroup.sortAll();

		pokerGroup.printAll();
		return pokerGroup;
	}

	private static strategyThreeAndTwoFirst(kingBomb: Array<number>, bombLevelGroups: Array<number>, bigLevelGroups: Array<number>): PokerGroup {
		let leftLevels = [];
		PokerHelper.arrayPushAll(leftLevels, PokerHelper.pokerArray);

		let pokerGroup = new PokerGroup();
		pokerGroup = PokerHelper.findThreeGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllLianDuiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllTwoGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllShunZiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllSingleGroups(pokerGroup, leftLevels);
		PokerHelper.checkLeftPokers(pokerGroup, leftLevels);

		pokerGroup = PokerHelper.addAllBigGroups(pokerGroup, kingBomb, bombLevelGroups, bigLevelGroups);
		pokerGroup.sortAll();
		pokerGroup.printAll();
		return pokerGroup;
	}

	private static strategyShunZiFirst(kingBomb: Array<number>, bombLevelGroups: Array<number>, bigLevelGroups: Array<number>): PokerGroup {
		let leftLevels = [];
		PokerHelper.arrayPushAll(leftLevels, PokerHelper.pokerArray);

		let pokerGroup = new PokerGroup();
		pokerGroup = PokerHelper.findAllShunZiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findThreeGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllLianDuiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllTwoGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllSingleGroups(pokerGroup, leftLevels);
		PokerHelper.checkLeftPokers(pokerGroup, leftLevels);

		pokerGroup = PokerHelper.addAllBigGroups(pokerGroup, kingBomb, bombLevelGroups, bigLevelGroups);
		pokerGroup.sortAll();
		pokerGroup.printAll();
		return pokerGroup;
	}

	private static strategyTwoFirst(kingBomb: Array<number>, bombLevelGroups: Array<number>, bigLevelGroups: Array<number>): PokerGroup {
		let leftLevels = [];
		PokerHelper.arrayPushAll(leftLevels, PokerHelper.pokerArray);
		let pokerGroup = new PokerGroup();
		pokerGroup = PokerHelper.findAllLianDuiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllTwoGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllShunZiGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findThreeGroups(pokerGroup, leftLevels);
		pokerGroup = PokerHelper.findAllSingleGroups(pokerGroup, leftLevels);
		PokerHelper.checkLeftPokers(pokerGroup, leftLevels);

		pokerGroup = PokerHelper.addAllBigGroups(pokerGroup, kingBomb, bombLevelGroups, bigLevelGroups);
		pokerGroup.sortAll();
		pokerGroup.printAll();
		return pokerGroup;
	}

	private static findFlyPokerSell(lastPokerSell: PokerSell): PokerSell {
		let straightCount = lastPokerSell == null ? 0 : lastPokerSell.getStraightCount();
		let minLevel = lastPokerSell == null ? 0 : lastPokerSell.getSellPokers()[0].level;

		let pokerSell: PokerSell = null;
		for (let group of PokerHelper.groups) {
			if (group.three.length >= 2) {
				let count = 0;
				let startIndex = 0;
				let lastLevel = 0;
				for (let i = 0; i < group.three.length; i++) {
					let pokers: Array<Poker> = group.three[i];
					if (pokers[0].level <= minLevel) {
						continue;
					}
					if (lastLevel == 0) {
						count++;
						startIndex = i;
					} else if (lastLevel + 1 == pokers[0].level) {
						count++;
						if (straightCount > 0 && straightCount == count) {
							break;
						}
					} else {
						count = 1;
						startIndex = i;
					}
					lastLevel = pokers[0].level;
				}

				if (straightCount != count) {
					continue;
				}

				if (group.three[startIndex][0].level <= minLevel) {
					continue;
				}

				let pokers: Array<Poker> = [];
				for (let i = startIndex; i < startIndex + count; i++) {
					PokerHelper.arrayPushAll(pokers, group.three[i]);
				}

				switch (lastPokerSell.getSellType()) {
					case SellType.THREE_STRAIGHT:
						pokerSell = new PokerSell(SellType.THREE_STRAIGHT, pokers, pokers[0].level);
						break;
					case SellType.THREE_STRAIGHT_WITH_SINGLE:
						if (group.single.length < count) {
							break;
						}
						for (let i = 0; i < count; i++) {
							pokers.push(group.single[i]);
						}
						pokerSell = new PokerSell(SellType.THREE_STRAIGHT_WITH_SINGLE, pokers, pokers[0].level);
						break;
					case SellType.THREE_STRAIGHT_WITH_DOUBLE:
						if (group.two.length < count) {
							break;
						}
						for (let i = 0; i < count; i++) {
							PokerHelper.arrayPushAll(pokers, group.two[i]);
						}
						pokerSell = new PokerSell(SellType.THREE_STRAIGHT_WITH_DOUBLE, pokers, pokers[0].level);
						break;
					default:
						break;
				}
			}
		}

		return pokerSell;
	}

	private static addAllBigGroups(pokerGroup: PokerGroup, kingBomb: Array<number>, bombLevelGroups: Array<number>, bigLevelGroups: Array<number>): PokerGroup {
		for (let bigPoker of bigLevelGroups) {
			for (let poker of PokerHelper.allPokerMap.get(bigPoker)) {
				pokerGroup.addSingleBig(poker);
			}
		}

		for (let bomb of bombLevelGroups) {
			pokerGroup.addBomb(PokerHelper.allPokerMap.get(bomb));
		}

		if (kingBomb.length > 0) {
			let kings: Array<Poker> = [];
			console.log("------------> ", kingBomb, PokerHelper.allPokerMap);
			for (let king of kingBomb) {
				console.log("------------> ", king, PokerHelper.allPokerMap.get(king));
				kings.push(PokerHelper.allPokerMap.get(king)[0]);
			}
			pokerGroup.addBomb(kings);
		}

		return pokerGroup;
	}

	private static checkLeftPokers(pokerGroup: PokerGroup, leftLevels: Array<number>) {
		for (let i = PokerLevel.LEVEL_3; i < leftLevels.length; i++) {
			if (leftLevels[i] <= 0) {
				continue;
			}
			if (leftLevels[i] == 1) {
				pokerGroup.addSingle(PokerHelper.allPokerMap.get(i)[0]);
			} else if (leftLevels[i] == 2) {
				let pokers: Array<Poker> = [];
				pokers.push(PokerHelper.allPokerMap.get(i)[PokerHelper.allPokerMap.get(i).length - 2]);
				pokers.push(PokerHelper.allPokerMap.get(i)[PokerHelper.allPokerMap.get(i).length - 1]);
				pokerGroup.addTwo(pokers);
			} else if (leftLevels[i] == 3) {
				pokerGroup.addThree(PokerHelper.allPokerMap.get(i));
			}

			leftLevels[i] = 0;
		}
	}

	private static findThreeGroups(pokerGroup: PokerGroup, leftLevels: Array<number>): PokerGroup {
		let three: Array<number> = [];
		for (let i = PokerLevel.LEVEL_3; i < leftLevels.length; i++) {
			if (leftLevels[i] <= 0) {
				continue;
			}

			if (leftLevels[i] == 3) {
				three.push(i);
				leftLevels[i] = 0;
			}
		}

		for (let th of three) {
			pokerGroup.addThree(PokerHelper.allPokerMap.get(th));
		}
		return pokerGroup;
	}

	private static findAllLianDuiGroups(pokerGroup: PokerGroup, leftLevels: Array<number>): PokerGroup {
		let lianziMap: Map<number, number> = new Map();
		for (let i = PokerLevel.LEVEL_3; i < PokerLevel.LEVEL_A; i++) {
			if (leftLevels[i] <= 0) {
				continue;
			}

			if (leftLevels[i] >= 2 && leftLevels[i] < 4) {
				lianziMap.set(i, leftLevels[i]);
			}
		}

		while (true) {
			let allSize = lianziMap.size;
			if (allSize < 3) {
				break;
			}

			let list = Array.from(lianziMap).map(item => item[0]);
			let start = list[0];
			let end = list[list.length - 1];
			// SimplePrinter.serverLog("+++++++++++ > lian start: " + start + " end: " + end);
			if (end - start < 2) {
				break;
			}

			let lianCount = 0;
			for (let i = start; i <= end; i++) {
				let va = lianziMap.get(i);
				if (!va) {
					va = -1;
				}
				if (va != -1) {
					lianCount++;
				} else {
					// SimplePrinter.serverLog("+++++++++++ > start: " + start + " lianCount: " + lianCount);
					if (lianCount >= 3) {
						let pokers: Array<Poker> = [];
						for (let x = start; x < start + lianCount; x++) {
							if (PokerHelper.allPokerMap.get(x).length > 2) {
								pokers.push(PokerHelper.allPokerMap.get(x)[PokerHelper.allPokerMap.get(x).length - 2]);
								pokers.push(PokerHelper.allPokerMap.get(x)[PokerHelper.allPokerMap.get(x).length - 1]);
							} else {
								PokerHelper.arrayPushAll(pokers, PokerHelper.allPokerMap.get(x));
							}
							lianziMap.delete(x);
							leftLevels[x] -= 2;
						}
						pokerGroup.liandui.push(pokers);
					} else if (lianCount == 1) {
						lianziMap.delete(start);
					} else if (lianCount == 2) {
						lianziMap.delete(start + 1);
					}
					lianCount = 0;
					break;
				}
			}


			if (lianCount != 0 && allSize == lianCount) {
				let pokers: Array<Poker> = [];
				for (let index of lianziMap.keys()) {
					if (PokerHelper.allPokerMap.get(index).length > 2) {
						pokers.push(PokerHelper.allPokerMap.get(index)[PokerHelper.allPokerMap.get(index).length - 2]);
						pokers.push(PokerHelper.allPokerMap.get(index)[PokerHelper.allPokerMap.get(index).length - 1]);
					} else {
						PokerHelper.arrayPushAll(pokers, PokerHelper.allPokerMap.get(index));
					}
					leftLevels[index] -= 2;
				}
				pokerGroup.liandui.push(pokers);
				break;
			}
		}

		return pokerGroup;
	}

	private static findAllShunZiGroups(pokerGroup: PokerGroup, leftLevels: Array<number>): PokerGroup {
		let maxShunzi: Array<number> = PokerHelper.findMaxShunzi(leftLevels);
		let maxSz: Array<Poker> = [];
		for (let sz of maxShunzi) {
			maxSz.push(PokerHelper.allPokerMap.get(sz)[0]);
		}
		if (maxSz.length > 0) {
			pokerGroup.addShunzi(maxSz);
		}

		let otherSz: Array<Array<number>> = PokerHelper.findAllShunZi(leftLevels);
		for (let other of otherSz) {
			if (other.length <= 0) {
				continue;
			}

			let szList = [];
			for (let sz of other) {
				szList.push(PokerHelper.allPokerMap.get(sz)[0]);
			}
			pokerGroup.addShunzi(szList);
		}
		return pokerGroup;
	}

	private static findAllTwoGroups(pokerGroup: PokerGroup, leftLevels: Array<number>): PokerGroup {
		let two = [];
		for (let i = PokerLevel.LEVEL_3; i < leftLevels.length; i++) {
			if (leftLevels[i] <= 0) {
				continue;
			}

			if (leftLevels[i] == 2) {
				two.push(i);
				leftLevels[i] = 0;
			}
		}

		for (let tw of two) {
			//            SimplePrinter.serverLog("========> two size: " + allPokerMap.get(tw).size());
			if (PokerHelper.allPokerMap.get(tw).length > 2) {
				let pokers = [];
				pokers.push(PokerHelper.allPokerMap.get(tw)[PokerHelper.allPokerMap.get(tw).length - 2]);
				pokers.push(PokerHelper.allPokerMap.get(tw)[PokerHelper.allPokerMap.get(tw).length - 1]);
				pokerGroup.addTwo(pokers);
			} else {
				pokerGroup.addTwo(PokerHelper.allPokerMap.get(tw));
			}
		}
		return pokerGroup;
	}


	private static findAllSingleGroups(pokerGroup: PokerGroup, leftLevels: Array<number>): PokerGroup {
		let single = [];
		for (let i = PokerLevel.LEVEL_3; i < leftLevels.length; i++) {
			if (leftLevels[i] <= 0) {
				continue;
			}

			if (leftLevels[i] == 1) {
				single.push(i);
				leftLevels[i] = 0;
			}
		}
		for (let sg of single) {
			pokerGroup.addSingle(PokerHelper.allPokerMap.get(sg)[0]);
		}
		return pokerGroup;
	}

	private static findMinShunzi(leftLevels: Array<number>): Array<number> {
		let shunzi = [];
		if (leftLevels.length < 5) {
			//牌数不足顺子数
			return shunzi;
		}

		let startLevel = 0;
		let lastLevel = 0;
		let lianCount = 0;
		for (let i = PokerLevel.LEVEL_3; i < leftLevels.length; i++) {
			if (leftLevels[i] <= 0) {
				continue;
			}

			if (lastLevel + 1 == i) {
				lianCount++;
			} else {
				lianCount = 1;
				startLevel = i;
			}

			lastLevel = i;
			if (lianCount == 5) {
				break;
			}
		}

		// SimplePrinter.serverLog("findMinShunzi lianCount: " +lianCount + " startLevel: " + startLevel + " last: " + lastLevel);

		if (lianCount != 5) {
			return shunzi;
		}

		for (let i = startLevel; i < startLevel + lianCount; i++) {
			shunzi.push(i);
			leftLevels[i] -= 1;
		}

		return shunzi;
	}

	private static findMaxShunzi(leftLevels: Array<number>): Array<number> {
		let shunzi = PokerHelper.findMinShunzi(leftLevels);

		//		printPokers(shunzi);
		//		printPokers(leftLevels);

		if (shunzi.length > 0) {
			//剩余的牌找出能和顺子组成最长的顺子
			let szMax = shunzi[shunzi.length - 1];

			// SimplePrinter.serverLog("===============> shunzi max poker: " + szMax + " len: " + leftLevels.length);

			while (szMax < leftLevels.length) {
				if (leftLevels[szMax + 1] <= 0) {
					break;
				}
				shunzi.push(szMax + 1);
				leftLevels[szMax + 1] -= 1;
				szMax = shunzi[shunzi.length - 1];
				//                SimplePrinter.serverLog("===============> shunzi 111 max poker: " + szMax + " len: " + leftLevels.length);
			}
		}

		return shunzi;
	}

	private static findAllShunZi(leftLevels: Array<number>): Array<Array<number>> {
		let shunzis: Array<Array<number>> = [];
		if (leftLevels.length < 5) {
			//牌数不足顺子数
			return shunzis;
		}

		//        SimplePrinter.serverLog("===============> findAllShunZi: ");
		//        printPokers(leftLevels);

		let startLevel = 0;
		let lastLevel = 0;
		let lianCount = 0;
		for (let i = PokerLevel.LEVEL_3; i < leftLevels.length; i++) {
			if (leftLevels[i] <= 0 && startLevel == 0) {
				continue;
			}

			if (startLevel == 0) {
				lianCount = 1;
				startLevel = i;
				lastLevel = i;
				continue;
			}

			if (leftLevels[i] > 0) {
				if (lastLevel + 1 == i) {
					lianCount++;
				} else {

					if (lianCount >= 5) {
						let shunzi = [];
						for (let x = startLevel; x < startLevel + lianCount; x++) {
							shunzi.push(x);
							leftLevels[x] -= 1;
						}
						shunzis.push(shunzi);
						//                        SimplePrinter.serverLog("find all 0 lianCount: " +lianCount + " startLevel: " + startLevel + " last: " + lastLevel);
					}

					startLevel = i;
					lianCount = 1;
				}
				lastLevel = i;
			}
		}

		//        SimplePrinter.serverLog("find all 1 lianCount: " +lianCount + " startLevel: " + startLevel + " last: " + lastLevel);

		if (lianCount >= 5) {
			let shunzi = [];
			for (let i = startLevel; i < startLevel + lianCount; i++) {
				shunzi.push(i);
				leftLevels[i] -= 1;
			}
		}

		return shunzis;
	}
}

// let poker1 = new Poker(PokerLevel.LEVEL_2, PokerType.DIAMOND);
// let poker2 = new Poker(PokerLevel.LEVEL_8, PokerType.SPADE);
// let lastPoker = [
// 	{level:PokerLevel.LEVEL_3, type:PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_4, type:PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_5, type:PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_6, type:PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_7, type:PokerType.CLUB},
// ]
// let pokerShell = PokerHelper.checkPokerType(lastPoker)
// console.log("=======> pokerShell:", pokerShell)

// let poker_h1 = new Poker(PokerLevel.LEVEL_Q, PokerType.DIAMOND);
// let poker_h2 = new Poker(PokerLevel.LEVEL_SMALL_KING, PokerType.SPADE);

// let handPoker:Poker[] = [
// 	{level:PokerLevel.LEVEL_3, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_4, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_5, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_6, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_7, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_7, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_7, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_8, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_10, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_K, type:PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_K, type:PokerType.SPADE},
// 	{level:PokerLevel.LEVEL_K, type:PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_A, type: PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_A, type: PokerType.DIAMOND},
// 	{level:PokerLevel.LEVEL_A, type: PokerType.SPADE},
// 	{level:PokerLevel.LEVEL_A, type: PokerType.HEART},
// 	{level:PokerLevel.LEVEL_2, type: PokerType.CLUB},
// 	{level:PokerLevel.LEVEL_SMALL_KING, type: PokerType.SPADE},
// 	{level:PokerLevel.LEVEL_BIG_KING, type: PokerType.SPADE},
// ];

// let hitPoker = PokerHelper.hint(handPoker, pokerShell.getSellPokers());

// console.log("=======> hitPoker:", hitPoker)

// let sell = PokerHelper.checkSellValid(pokerShell, hitPoker)

// console.log("=======> sell:", sell)

